import java.util.ArrayList;
import java.util.List;

/**
 * 给定一个整数数组nums，其中恰好有两个元素只出现一次，其余所有元素均出现两次。 找出只出现一次的那两个元素。你可以按 任意顺序 返回答案。
 *
 * 进阶：你的算法应该具有线性时间复杂度。你能否仅使用常数空间复杂度来实现？
 *
 * 示例 1：
 * 输入：nums = [1,2,1,3,2,5]
 * 输出：[3,5]
 * 解释：[5, 3] 也是有效的答案。
 *
 * 示例 2：
 * 输入：nums = [-1,0]
 * 输出：[-1,0]
 *
 * 示例 3：
 * 输入：nums = [0,1]
 * 输出：[1,0]
 *
 * 提示：
 * 2 <= nums.length <= 3 * 104
 * -231 <= nums[i] <= 231 - 1
 * 除两个只出现一次的整数外，nums 中的其他数字都出现两次
 *
 * 来源：力扣（LeetCode）
 * 链接：https://leetcode-cn.com/problems/single-number-iii
 * 著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。
 */
public class Q00260m {

    /**
     * 参考了答案
    */
    public int[] singleNumber(int[] nums) {
        // 假设两个不同的数字为a,b
        // 1.全部异或，则结果等于a^b(显而易见不等于0)
        int x = 0;
        for (int num : nums) {
            x ^= num;
        }
        // 2.取最低位为1的数字，它一定是由a和b当中对应位置一个为0且另一个为1异或得到
        int digit = 0;
        while ((x & 1) == 0) {
            x >>= 1;
            digit++;
        }
        // 3.分组
        x = 1 << digit;
        List<Integer> zeros = new ArrayList<>();
        List<Integer> ones = new ArrayList<>();
        for (int num : nums) {
            if ((num & x) == 0) {
                zeros.add(num);
            } else {
                ones.add(num);
            }
        }
        // 4.组内分别异或
        int[] ans = new int[2];
        for (Integer i : zeros) {
            ans[0] ^= i;
        }
        for (Integer i : ones) {
            ans[1] ^= i;
        }
        return ans;
    }
}
